home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / view.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-18  |  7.9 KB  |  343 lines

  1. /* Random access file viewer. PC specific */
  2.  
  3. #include <stdio.h>
  4. #include <conio.h>
  5. #include "global.h"
  6. #include "session.h"
  7. #include "tty.h"
  8. #include "commands.h"
  9. #include "socket.h"
  10.  
  11. #include <dos.h>
  12.  
  13. static long lineseek __ARGS((FILE *fp,long offset,int nlines,int width));
  14. static int ctlproc __ARGS((int c));
  15. void view __ARGS((int s, void *p1, void*p2));
  16.  
  17. extern char NoRead[];
  18. extern int Viewfeatures;
  19. extern char readmeFile[];
  20.  
  21. int
  22. doview(argc,argv,p)
  23. int argc;
  24. char *argv[];
  25. void *p;
  26. {
  27. char fname[256];
  28. FILE *fp;
  29.  
  30.     /*allow only keyboard users to access the view command*/
  31.     if(Curproc->input != Command->input) {
  32.         tputs("The 'view' command can only be executed from the command session.\nTry the 'more' command, instead!\n\n");
  33.         return 0;
  34.     }
  35.  
  36.     strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
  37.     if((fp = fopen(fname,READ_TEXT)) == NULLFILE)    {
  38.         tprintf(NoRead,fname,sys_errlist[errno]);
  39.         return 1;
  40.     }
  41. #if 1
  42.     newproc("view",512,view,0,(void *)fp,(argv[1] == readmeFile) ? (void *) "Reviewing the new features file" : (void *) strdup(argv[1]),(argv[1] == readmeFile) ? 0 : 2);
  43. #else
  44.     newproc("view",512,view,0,(void *)fp,(void *)argv[1],0);
  45. #endif
  46.     return 0;    
  47. }
  48. /* Random-access file display program. Used both to read local
  49.  * files with the "view" command, and by the FTP client to view
  50.  * directory listings, temporary copies of read files, etc.
  51.  *
  52.  */
  53. void
  54. view(s,p1,p2)
  55. int s;        /* If non-zero, poll interval for a changing file */
  56. void *p1;    /* Open file pointer to read from */
  57. void *p2;    /* If non-null, name to give to session. We free it */
  58. {
  59.     struct session *sp;
  60.     FILE *fp;
  61.     char *name;
  62.     int c;
  63.     long offset = 0;
  64.     int row,col;
  65.     int cols;
  66.     int rows;
  67.     int32 polldelay = 0;
  68.     struct text_info text_info;
  69.  
  70.     gettextinfo(&text_info);
  71.     cols = text_info.screenwidth;
  72.     rows = text_info.screenheight-1;    /* Allow for status line */
  73.  
  74.     fp = (FILE *)p1;
  75. /*    if(p2 != NULL)        */
  76.         name = (char *)p2;
  77. /*    else
  78.         name = fpname(fp);    */
  79.  
  80.     if((sp = newsession(name,VIEW,0)) == NULLSESSION)
  81.         return;
  82.  
  83. /*    if(p2 != NULL)
  84.         free(name);        */
  85.  
  86.     if(s != 0)
  87.         polldelay = s;
  88. /*    sp->ctlproc = ctlproc;        */
  89.     /* Put tty into raw mode so single-char responses will work */
  90.     sp->ttystate.echo = sp->ttystate.edit = 0;
  91.     for(;;){
  92.         fseek(fp,offset,SEEK_SET);
  93.         clrscr ();
  94. /*        tputc(FF);    */    /* Clear screen */
  95.         /* Display a screen's worth of data, keeping track of
  96.          * cursor location so we know when the screen is full
  97.          */
  98.         col = row = 0;
  99.         while((c = getc(fp)),c != EOF){
  100.             switch(c){
  101.             case '\n':
  102.                 row++;
  103.                 col = 0;
  104.                 break;
  105.             case '\t':
  106.                 if(col < cols - 8)
  107.                     col = (col + 8) & ~7;
  108.                 break;
  109.             default:
  110.                 col++;
  111.                 break;
  112.             }
  113.             if(col >= cols){
  114.                 /* Virtual newline caused by wraparound */
  115.                 col = 0;
  116.                 row++;
  117.             }
  118.             if(row >= rows)
  119.                 break;    /* Screen now full */
  120.             tputc(c);
  121.         }
  122. #ifdef    notdef
  123.         if(feof(fp) && offset != 0){
  124.             /* Hit end of file. Back up proper number of
  125.              * lines and try again.
  126.              */
  127.             offset = lineseek(fp,offset,row-rows,cols);
  128.             continue;
  129.         }
  130. #endif
  131.         tflush();
  132.         /* If we hit the end of the file and the file may be
  133.          * growing, then set an alarm to time out the getchar()
  134.          */
  135.         do {
  136.             if(feof(fp) && polldelay != 0){
  137.                 alarm(polldelay);
  138.             }
  139.             c = recvchar(Curproc->input);
  140.             alarm(0L);    /* Cancel alarm */
  141.             if(c != -1 || errno != EALARM)
  142.                 break;    /* User hit key */
  143.             /* Alarm timeout; see if more data arrived by
  144.              * clearing the EOF flag, trying to read
  145.              * another byte, and then testing EOF again
  146.              */
  147.             clearerr(fp);
  148.             (void)getc(fp);
  149.             c = ' ';    /* Simulate a no-op keypress */
  150.         } while(feof(fp));
  151.         switch(c){
  152.         case 'h':    /* Home */
  153.         case 'H':
  154.         case '<':    /* For emacs users */
  155.             offset = 0;
  156.             break;
  157.         case 'e':    /* End */
  158.         case '>':    /* For emacs users */
  159.             fseek(fp,0L,SEEK_END);
  160.             offset = lineseek(fp,ftell(fp),-rows,cols);
  161.             break;
  162.         case CTLD:    /* Down one half screen (for VI users) */
  163.             if(!feof(fp))
  164.                 offset = lineseek(fp,offset,rows/2,cols);
  165.             break;
  166.         case CTLU:    /* Up one half screen (for VI users) */
  167.             offset = lineseek(fp,offset,-rows/2,cols);
  168.             break;
  169.         case 'd':    /* down line */
  170.         case CTLN:    /* For emacs users */
  171.         case 'j':    /* For vi users */
  172.             if(!feof(fp))
  173.                 offset = lineseek(fp,offset,1,cols);
  174.             break;
  175.         case 'D':    /* Down page */
  176.         case CTLV:    /* For emacs users */
  177.             if(!feof(fp))
  178.                 offset = lineseek(fp,offset,rows,cols);
  179.             break;
  180.         case 'u':    /* up line */
  181.         case CTLP:    /* for emacs users */
  182.         case 'k':    /* for vi users */
  183.             offset = lineseek(fp,offset,-1,cols);
  184.             break;
  185.         case 'U':    /* Up page */
  186.         case 'v':    /* for emacs users */
  187.             offset = lineseek(fp,offset,-rows,cols);
  188.             break;
  189.         case CTLC:
  190.         case 'q':
  191.         case 'Q':
  192.         case ESC:
  193.             goto done;
  194.         default:
  195.             break;    /* Redisplay screen */
  196.         }
  197.     }
  198. done:    fclose(fp);
  199.     freesession(sp);
  200. }
  201. /* Given a starting offset into an open file stream, scan forwards
  202.  * or backwards the specified number of lines and return a pointer to the
  203.  * new offset.
  204.  */
  205. static long
  206. lineseek(fp,start,nlines,width)
  207. FILE *fp;    /* Open file stream */
  208. long start;    /* Offset to start searching backwards from */
  209. int nlines;    /* Number of lines to move forward (+) or back (-) */
  210. int width;    /* Screen width (max line size) */
  211. {
  212.     long offset;
  213.     long *pointers;
  214.     int col = 0;
  215.     int c;
  216.     int newlines = 0;
  217.  
  218.     if(nlines == 0)
  219.         return start;    /* Nothing to do */
  220.  
  221.     if(nlines > 0){        /* Look forward requested # of lines */
  222.         fseek(fp,start,SEEK_SET);
  223.         col = 0;
  224.         while((c = getc(fp)),c != EOF){
  225.             switch(c){
  226.             case '\n':
  227.                 newlines++;
  228.                 col = 0;
  229.                 break;
  230.             case '\t':
  231.                 if(col < width - 8)
  232.                     col = (col + 8) & ~7;
  233.                 break;
  234.             default:
  235.                 col++;
  236.                 break;
  237.             }
  238.             if(col >= width){
  239.                 /* Virtual newline caused by wraparound */
  240.                 col = 0;
  241.                 newlines++;
  242.             }
  243.             if(newlines >= nlines)
  244.                 break;    /* Found requested count */
  245.         }
  246.         return ftell(fp);    /* Could be EOF */
  247.     }
  248.     /* Backwards scan (the hardest)
  249.      * Start back up at most (width + 2) chars/line from the start.
  250.      * This handles full lines followed by expanded newline
  251.      * sequences
  252.      */
  253.     nlines = -nlines;
  254.     offset = (width + 2)*(nlines + 1);
  255.     if(offset > start)
  256.         offset = 0;    /* Go to the start of the file */
  257.     else
  258.         offset = start - offset;
  259.     fseek(fp,offset,SEEK_SET);
  260.  
  261.     /* Keep a circular list of the last 'nlines' worth of offsets to
  262.      * each line, starting with the first
  263.      */
  264.     pointers = (int32 *)calloc(sizeof(long),nlines);
  265.     pointers[newlines++ % nlines] = offset;
  266.  
  267.     /* Now count newlines up but not including the original
  268.      * starting point
  269.      */
  270.     col = 0;
  271.     for(;;){
  272.         c = getc(fp);
  273.         switch(c){
  274.         case EOF:
  275.             goto done;
  276.         case '\n':
  277.             col = 0;
  278.             offset = ftell(fp);
  279.             if(offset >= start)
  280.                 goto done;
  281.             pointers[newlines++ % nlines] = offset;
  282.             break;
  283.         case '\t':
  284.             if(col < width - 8)
  285.                 col = (col + 8) & ~7;
  286.             break;
  287.         default:
  288.             col++;
  289.             break;
  290.         }
  291.         if(col >= width){
  292.             /* Virtual newline caused by wraparound */
  293.             col = 0;
  294.             offset = ftell(fp);
  295.             if(offset >= start)
  296.                 goto done;
  297.             pointers[newlines++ % nlines] = offset;
  298.         }
  299.     }
  300.     done:;
  301.     if(newlines >= nlines){
  302.         /* Select offset pointer nlines back */
  303.         offset = pointers[newlines % nlines];
  304.     } else {
  305.         /* The specified number of newlines wasn't seen, so
  306.          * go to the start of the file
  307.          */
  308.         offset = 0;
  309.     }
  310.     free(pointers);
  311.     return offset;
  312. }
  313.  
  314. /* Handle special keystrokes */
  315. static int
  316. ctlproc(c)
  317. int c;
  318. {
  319.     switch(c){
  320.     case 256 + 71:    /* HOME */
  321.         usputc(Current->input, 'h');
  322.         break;
  323.     case 256 + 72:    /* Cursor up */
  324.         usputc(Current->input, 'u');
  325.         break;
  326.     case 256 + 73:    /* Page up */
  327.         usputc(Current->input, 'U');
  328.         break;
  329.     case 256 + 79:    /* End */
  330.         usputc(Current->input, 'e');
  331.         break;
  332.     case 256 + 80:    /* Cursor down */
  333.         usputc(Current->input, 'd');
  334.         break;
  335.     case 256 + 81:    /* Page down */
  336.         usputc(Current->input, 'D');
  337.         break;
  338.     }
  339.     usflush(Current->input);
  340.     return c;
  341. }
  342.  
  343.